package edu.princeton.cogsci.wn;

import java.util.*;

/**
 * The MarkupText object is used to hold the information describing the
 * tags in the glosses. Only one layer of tags is supported, and each tag
 * can have an argument list. Text without a tag is given an invisible tag
 * named "text", which is displayed without the tag markings when getMarkup
 * is called.
 */

public class MarkupText
{
    private String markup;
    public Vector tags;

    public class Tag
    {
	public class Def
	{
	    private String name;
	    private Hashtable params;
	    Def( String def )
	    {
		params = new Hashtable( );
		StringTokenizer strtok = new StringTokenizer( def, " " );
		name = strtok.nextToken( );
		while ( strtok.hasMoreTokens( ) )
		    {
			String param = strtok.nextToken( );
			StringTokenizer strtok2 = new StringTokenizer( param, "=" );
			params.put( strtok2.nextToken( ), strtok2.nextToken( ) );
		    }
	    }
	    
	    public String getName( )
	    {
		return name;
	    }

	    public void setName( String name )
	    {
		this.name = name;
	    }

	    public String getParam( String key )
	    {
		return ( String )params.get( key );
	    }

	    public void setParam( String key, String p )
	    {
		params.put( key, p );
	    }

	    public void removeParam( String key )
	    {
		params.remove( key );
	    }

	    public String toString( )
	    {
		String res = new String( name );
		Enumeration keys = params.keys( );
		while ( keys.hasMoreElements( ) )
		    {
			String key = ( String )keys.nextElement( );
			res += " " + key + "=" + params.get( key );
		    }
		return res;
	    }
	}

	private String markup;
	private Def def;
	private String text;
	private int offset;

	Tag( String markup, int offset )
	{
	    this.offset = offset;
	    this.markup = markup;
	    if ( markup.charAt( 0 ) == '<' )
		{
		    StringTokenizer strtok = new StringTokenizer( markup, "><" );
		    def = new Def( strtok.nextToken( ) );
		    text = strtok.nextToken( );
		}
	    else
		{
		    def = new Def( "text" );
		    text = markup;
		}
	}

	public int getOffset( )
	{
	    return offset;
	}

	public Def getDef( )
	{
	    return def;
	}

	public void setDef( Def def )
	{
	    this.def = def;
	}

	public String getText( )
	{
	    return text;
	}

	public void setText( String text )
	{
	    this.text = text;
	}

	public String getMarkup( )
	{
	    return markup;
	}

	public String toString( )
	{
	    if ( def.getName( ).equals( "text" ) )
		 return text;
	    return "<" + def.toString( ) + ">" + text + "</" + def.getName( ) + ">";
	}
    }

    public MarkupText( String markup )
    {
	setMarkup( markup );
    }

    public void setMarkup( String markup )
    {
	this.markup = markup;
	parse( );
    }

    public String getMarkup( )
    {
	String res = "";
	for ( int i = 0; i < tags.size( ); i++ )
	    res += tags.get( i ).toString( );
	return res;
    }

    public String toString( )
    {
	String res = "";
	for ( int i = 0; i < tags.size( ); i++ )
	    {
		Tag t = ( Tag )tags.get( i );
		res += t.getText( );
	    }
	return res;
    }

    public Tag[] getTags( )
    {
	Tag[] t = new Tag[tags.size( )];
	tags.copyInto( t );
	return t;
    }

    public Tag getTagAt( int index )
    {
	Tag[] t = getTags( );
	for ( int i = 0; i < t.length; i++ )
	    if ( index >= t[i].getOffset( ) && ( i == t.length - 1 || index < t[i + 1].getOffset( ) ) )
		return t[i];
	return null;
    }

    public Tag createTag( String markup, int offset )
    {
	return new Tag( markup, offset );
    }

    public void replaceTag( Tag t, Tag[] rs )
    {
	int index = tags.indexOf( t );
	if ( index == -1 )
	    return;
	tags.remove( t );
	for ( int i = rs.length; i != 0; i-- )
	    tags.add( index, rs[i - 1] );
    }

    public void insertTag( Tag it, int insertStart, int insertEnd )
    {
	try
	    {
	Tag t = getTagAt( insertStart );
	
	if ( !t.getDef( ).getName( ).equals( "text" ) )
	    return;

	Vector vec = new Vector( );
	if ( insertStart != t.getOffset( ) )
	    {
		String leftMargin = t.getText( ).substring( 0, insertStart - t.getOffset( ) );
		vec.add( createTag( leftMargin, t.getOffset( ) ) );
	    }

	vec.add( it );

	if ( insertEnd != ( t.getText( ).length( ) + t.getOffset( ) ) )
	    {
		String rightMargin = t.getText( ).substring( insertEnd - t.getOffset( ) );
		vec.add( createTag( rightMargin, insertEnd ) );
	    }

	Tag[] ts = new Tag[vec.size( )];
	vec.copyInto( ts );

	replaceTag( t, ts );
	    }
	catch ( Exception e )
	    {
		e.printStackTrace( );
	    }
    }

    public void parse( )
    {
	tags = new Vector( );
	String targ = markup;
	int offset = 0;
	while ( targ.length( ) != 0 )
	    {
		if ( targ.charAt( 0 ) != '<' )
		    {
			String tagTxt;
			if ( targ.indexOf( '<' ) == -1 )
			    tagTxt = targ;
			else  
			    tagTxt = targ.substring( 0, targ.indexOf( '<' ) );
			tags.add( new Tag( tagTxt, offset ) );
			targ = targ.substring( tagTxt.length( ) );
			offset += tagTxt.length( );
		    }
		else
		    {
			int end = targ.indexOf( "</" );
			end = targ.indexOf( ">", end ) + 1;
			String tagTxt = targ.substring( 0, end );
			tags.add( new Tag( tagTxt, offset ) );
			targ = targ.substring( tagTxt.length( ) );
			offset += tagTxt.length( );
		    }
	    }
    }
}
